﻿#pragma once

#include <string>
#include <fast_io/fast_io_freestanding.h>

class TextHolder {
public:
	union {
		char8_t inlineText[16]{};  // 0x0000
		char8_t* pText;            // 0x0000
	};

	size_t textLength{};         // 0x0010
	size_t alignedTextLength{};  // 0x0018

public:
	constexpr TextHolder() = default;

	constexpr TextHolder(TextHolder const& copy) {
		if (copy.textLength < 16) {
			textLength = copy.textLength;
			alignedTextLength = copy.alignedTextLength;

			if consteval {  // constexpr
				for (size_t i = 0; i < 16; ++i)
					inlineText[i] = copy.inlineText[i];
			} else {
				fast_io::freestanding::my_memcpy(inlineText, copy.inlineText, 16);
			}
		} else {
			fast_io::freestanding::my_memset(this, 0, sizeof(TextHolder));

			textLength = copy.textLength;

			pText = reinterpret_cast<char8_t*>(malloc(textLength));
			alignedTextLength = textLength;
			if (pText != nullptr && copy.pText != nullptr) 
				fast_io::freestanding::my_memcpy(pText, copy.pText, textLength);
		}
	}

	constexpr TextHolder(TextHolder&& move) {
		deleteText();
		if (move.textLength < 16) {
			textLength = move.textLength;
			alignedTextLength = move.alignedTextLength;

			if consteval {  // constexpr
				for (size_t i = 0; i < 16; ++i) {
					inlineText[i] = move.inlineText[i];
					move.inlineText[i] = (char8_t)0;
				}
			} else {
				fast_io::freestanding::my_memcpy(inlineText, move.inlineText, 16);
				fast_io::freestanding::my_memset(std::addressof(move), 0, sizeof(TextHolder));
			}
		} else {
			std::swap(textLength, move.textLength);
			std::swap(alignedTextLength, move.alignedTextLength);
			std::swap(pText, move.pText);
			move.deleteText();
		}
	}

	constexpr TextHolder& operator=(TextHolder const& copy) {
		deleteText();

		if (copy.textLength < 16) {
			textLength = copy.textLength;
			alignedTextLength = copy.alignedTextLength;

			if consteval {  // constexpr
				for (size_t i = 0; i < 16; ++i)
					inlineText[i] = copy.inlineText[i];
			} else {
				fast_io::freestanding::my_memcpy(inlineText, copy.inlineText, 16);
			}
		} else {
			fast_io::freestanding::my_memset(this, 0, sizeof(TextHolder));

			textLength = copy.textLength;

			pText = reinterpret_cast<char8_t*>(malloc(textLength));
			alignedTextLength = textLength;
			if (pText != nullptr && copy.pText != nullptr)
				fast_io::freestanding::my_memcpy(pText, copy.pText, textLength);
		}
		return *this;
	}

	constexpr TextHolder& operator=(TextHolder&& move) {
		deleteText();
		if (move.textLength < 16) {
			textLength = move.textLength;
			alignedTextLength = move.alignedTextLength;

			if consteval {  // constexpr
				for (size_t i = 0; i < 16; ++i) {
					inlineText[i] = move.inlineText[i];
					move.inlineText[i] = (char8_t)0;
				}
			} else {
				fast_io::freestanding::my_memcpy(inlineText, move.inlineText, 16);
				fast_io::freestanding::my_memset(std::addressof(move), 0, sizeof(TextHolder));
			}
		} else {
			std::swap(textLength, move.textLength);
			std::swap(alignedTextLength, move.alignedTextLength);
			std::swap(pText, move.pText);
			move.deleteText();
		}
		return *this;
	}

	constexpr TextHolder& operator=(const std::u8string_view str) {
		if (const auto sz = str.size(); sz < 16) {
			textLength = str.size();
			alignedTextLength = textLength;

			if consteval {  // constexpr
				for (size_t i = 0; i < sz; ++i)
					inlineText[i] = str[i];
				for (size_t i = sz; i < 16; ++i)
					inlineText[i] = (char8_t)0;
			} else {
				fast_io::freestanding::my_memset(inlineText, 0, 16);
				fast_io::freestanding::my_memcpy(inlineText, str.data(), sz);
			}
		} else {
			fast_io::freestanding::my_memset(this, 0, sizeof(TextHolder));

			textLength = str.size();

			pText = reinterpret_cast<char8_t*>(malloc(textLength));
			alignedTextLength = textLength;
			if (pText != nullptr)
				fast_io::freestanding::my_memcpy(pText, str.data(), textLength);
		}
		return *this;
	}

	constexpr TextHolder(const std::u8string_view str) {
		if (const auto sz = str.size(); sz < 16) {
			textLength = str.size();
			alignedTextLength = textLength;

			if consteval {  // constexpr
				for (size_t i = 0; i < sz; ++i)
					inlineText[i] = str[i];
				for (size_t i = sz; i < 16; ++i)
					inlineText[i] = (char8_t)0;
			} else {
				fast_io::freestanding::my_memset(inlineText, 0, 16);
				fast_io::freestanding::my_memcpy(inlineText, str.data(), sz);
			}
		} else {
			fast_io::freestanding::my_memset(this, 0, sizeof(TextHolder));

			textLength = str.size();

			pText = reinterpret_cast<char8_t*>(malloc(textLength));
			alignedTextLength = textLength;
			if (pText != nullptr)
				fast_io::freestanding::my_memcpy(pText, str.data(), textLength);
		}
	}

	constexpr TextHolder(void* ptr, size_t sizeOfData) {
		if (sizeOfData < 16) {
			textLength = sizeOfData;
			alignedTextLength = sizeOfData;
			if consteval {
				for (size_t i = 0; i < sizeOfData; ++i)
					inlineText[i] = *reinterpret_cast<char8_t*>((uintptr_t)ptr + i);
				for (size_t i = sizeOfData; i < 16; ++i)
					inlineText[i] = (char8_t)0;
			} else {
				fast_io::freestanding::my_memset(inlineText, 0, 16);
				fast_io::freestanding::my_memcpy(inlineText, ptr, sizeOfData);
			}
		} else {
			fast_io::freestanding::my_memset(this, 0, sizeof(TextHolder));

			textLength = sizeOfData;

			pText = reinterpret_cast<char8_t*>(malloc(textLength));
			alignedTextLength = textLength;
			if (pText != nullptr)
				fast_io::freestanding::my_memcpy(pText, ptr, textLength);
		}
	}

	constexpr void deleteText() {
		if (alignedTextLength >= 16 && pText != nullptr) 
			free(pText);
	}

	constexpr ~TextHolder() {
		this->deleteText();
	}

	inline constexpr char8_t* getText() {
		if (alignedTextLength < 16)
			return this->inlineText;
		else
			return this->pText;
	}

	inline constexpr std::u8string_view getString() const {
		if (alignedTextLength < 16)
			return std::u8string_view{this->inlineText, textLength};
		else
			return std::u8string_view{this->pText, textLength};
	}

	inline constexpr size_t getTextLength() const {
		return textLength;
	}

	void constexpr setText(std::u8string_view str) {
		deleteText();
		if (const auto sz = str.size(); sz < 16) {
			textLength = str.size();
			alignedTextLength = textLength;

			if consteval {  // constexpr
				for (size_t i = 0; i < sz; ++i)
					inlineText[i] = str[i];
				for (size_t i = sz; i < 16; ++i)
					inlineText[i] = (char8_t)0;
			} else {
				fast_io::freestanding::my_memset(inlineText, 0, 16);
				fast_io::freestanding::my_memcpy(inlineText, str.data(), sz);
			}
		} else {
			fast_io::freestanding::my_memset(this, 0, sizeof(TextHolder));

			textLength = str.size();

			pText = reinterpret_cast<char8_t*>(malloc(textLength));
			alignedTextLength = textLength;
			if (pText != nullptr)
				fast_io::freestanding::my_memcpy(pText, str.data(), textLength);
		}
	}

	void constexpr setText(const char8_t* c, size_t size) {
		deleteText();
		if (size < 16) {
			textLength = size;
			alignedTextLength = textLength;

			if consteval {  // constexpr
				for (size_t i = 0; i < size; ++i)
					inlineText[i] = c[i];
				for (size_t i = size; i < 16; ++i)
					inlineText[i] = (char8_t)0;
			} else {
				fast_io::freestanding::my_memset(inlineText, 0, 16);
				fast_io::freestanding::my_memcpy(inlineText, c, size);
			}
		} else {
			fast_io::freestanding::my_memset(this, 0, sizeof(TextHolder));

			textLength = size;

			pText = reinterpret_cast<char8_t*>(malloc(textLength));
			alignedTextLength = textLength;
			if (pText != nullptr)
				fast_io::freestanding::my_memcpy(pText, c, textLength);
		}
	}

	void constexpr resetWithoutDelete() {
		*getText() = 0;
		textLength = 0;
	}
};

class TextHolder_view {
public:
	union {
		char8_t inlineText[16]{};  // 0x0000
		char8_t* pText;            // 0x0000
	};

	size_t textLength{};         // 0x0010
	size_t alignedTextLength{};  // 0x0018

public:
	constexpr TextHolder_view() = default;

	constexpr TextHolder_view(TextHolder_view const& copy) = default;

	constexpr TextHolder_view(TextHolder_view&& move) = default;

	constexpr TextHolder_view& operator=(TextHolder_view const& copy) = default;

	constexpr TextHolder_view& operator=(TextHolder_view&& move) = default;

	constexpr TextHolder_view(std::u8string_view str) {
		if (const auto sz = str.size(); sz < 16) {
			textLength = str.size();
			alignedTextLength = textLength;

			if consteval {  // constexpr
				for (size_t i = 0; i < sz; ++i)
					inlineText[i] = str[i];
				for (size_t i = sz; i < 16; ++i)
					inlineText[i] = (char8_t)0;
			} else {
				fast_io::freestanding::my_memset(inlineText, 0, 16);
				fast_io::freestanding::my_memcpy(inlineText, str.data(), sz);
			}
		} else {
			if consteval {  // constexpr
				for (size_t i = 0; i < 16; ++i)
					inlineText[i] = (char8_t)0;
			} else {
				fast_io::freestanding::my_memset(this, 0, sizeof(TextHolder));
			}
			
			size_t size = str.size();
			textLength = size;

			pText = const_cast<char8_t*>(str.data());

			alignedTextLength = size;
		}
	}

	constexpr TextHolder_view(const char8_t* c, size_t size) {
		if (size < 16) {
			textLength = size;
			alignedTextLength = textLength;

			if consteval {  // constexpr
				for (size_t i = 0; i < size; ++i)
					inlineText[i] = c[i];
				for (size_t i = size; i < 16; ++i)
					inlineText[i] = (char8_t)0;
			} else {
				fast_io::freestanding::my_memset(inlineText, 0, 16);
				fast_io::freestanding::my_memcpy(inlineText, c, size);
			}
		} else {
			if consteval {  // constexpr
				for (size_t i = 0; i < 16; ++i)
					inlineText[i] = (char8_t)0;
			} else {
				fast_io::freestanding::my_memset(this, 0, sizeof(TextHolder));
			}

			textLength = size;

			pText = const_cast<char8_t*>(c);

			alignedTextLength = size;
		}
	}

	constexpr void setText(std::u8string_view str) {
		if (const auto sz = str.size(); sz < 16) {
			textLength = str.size();
			alignedTextLength = textLength;

			if consteval {  // constexpr
				for (size_t i = 0; i < sz; ++i)
					inlineText[i] = str[i];
				for (size_t i = sz; i < 16; ++i)
					inlineText[i] = (char8_t)0;
			} else {
				fast_io::freestanding::my_memset(inlineText, 0, 16);
				fast_io::freestanding::my_memcpy(inlineText, str.data(), sz);
			}
		} else {
			if consteval {  // constexpr
				for (size_t i = 0; i < 16; ++i)
					inlineText[i] = (char8_t)0;
			} else {
				fast_io::freestanding::my_memset(this, 0, sizeof(TextHolder));
			}

			size_t size = str.size();
			textLength = size;

			pText = const_cast<char8_t*>(str.data());

			alignedTextLength = size;
		}
	}

	constexpr void setText(const char8_t* c, size_t size) {
		if (size < 16) {
			textLength = size;
			alignedTextLength = textLength;

			if consteval {  // constexpr
				for (size_t i = 0; i < size; ++i)
					inlineText[i] = c[i];
				for (size_t i = size; i < 16; ++i)
					inlineText[i] = (char8_t)0;
			} else {
				fast_io::freestanding::my_memset(inlineText, 0, 16);
				fast_io::freestanding::my_memcpy(inlineText, c, size);
			}
		} else {
			if consteval {  // constexpr
				for (size_t i = 0; i < 16; ++i)
					inlineText[i] = (char8_t)0;
			} else {
				fast_io::freestanding::my_memset(this, 0, sizeof(TextHolder));
			}

			textLength = size;

			pText = const_cast<char8_t*>(c);

			alignedTextLength = size;
		}
	}

	inline constexpr char8_t* getText() {
		if (alignedTextLength < 16)
			return this->inlineText;
		else
			return this->pText;
	}

	inline constexpr std::u8string_view getString() const {
		if (alignedTextLength < 16)
			return std::u8string_view{this->inlineText, textLength};
		else
			return std::u8string_view{this->pText, textLength};
	}

	inline constexpr size_t getTextLength() const {
		return textLength;
	}
};

class GamerTextHolder {
public:
	union {
		char8_t inlineText[16]{};  // 0x0000
		char8_t* pText;            // 0x0000
	};

	size_t textLength{};         // 0x0010
	size_t alignedTextLength{};  // 0x0018

public:
	GamerTextHolder() {
		fast_io::freestanding::my_memset(this, 0, sizeof(GamerTextHolder));
	}

	char8_t* getText() {
		if (alignedTextLength < 16)
			return this->inlineText;
		else
			return this->pText;
	}

	std::u8string_view getString() const {
		if (alignedTextLength < 16)
			return std::u8string_view{this->inlineText, textLength};
		else
			return std::u8string_view{this->pText, textLength};
	}

	void copyFrom(TextHolder* copy);

	void deleteText();
};